<!--
 * Copyright © 2022
 * @Author: zhangxiang
 * @Date: 2022-11-21 17:13:52
 * @LastEditors: zhangxiang
 * @LastEditTime: 2023-07-18 15:23:03
 * @Description:
 *
-->

<template>
  <MyContainer class="container">
    <MyHeader class="header">
      <el-button
        size="medium"
        style="margin-left: auto"
        type="primary"
        icon="el-icon-plus"
        @click="createClick"
      >添加安全组规则</el-button>
    </MyHeader>
    <MyMain class="main">
      <el-table
        v-loading="loading"
        class="common-table"
        :data="list"
        stripe
        header-cell-class-name="listHeaderCell"
        :header-cell-style="{ color: '#696969' }"
      >
        <el-table-column
          prop="direction"
          label="规则方向"
          min-width="120"
          show-overflow-tooltip
        />
        <el-table-column
          prop="authObj"
          label="授权对象"
          min-width="150"
          show-overflow-tooltip
        />
        <el-table-column
          prop="protocol"
          label="协议类型"
          min-width="120"
          show-overflow-tooltip
        />
        <el-table-column
          prop="portRange"
          label="端口范围"
          min-width="150"
          show-overflow-tooltip
        />
        <el-table-column
          prop="policy"
          label="授权策略"
          min-width="120"
          show-overflow-tooltip
        />
        <el-table-column prop="createDate" label="创建时间" width="170" />
        <el-table-column label="操作" width="170">
          <template slot-scope="scope">
            <el-button
              type="primary"
              size="mini"
              style="height: 22px; padding: 0 10px"
              :disabled="isCloudPrivate"
              @click="editClick(scope.row)"
            >修改</el-button>
            <el-popover
              :ref="`popover-delete-${scope.$index}`"
              placement="top"
              width="300"
              style="margin-left: 10px"
            >
              <p>是否确认删除该安全组规则？</p>
              <div style="text-align: right; margin: 0">
                <el-button
                  size="mini"
                  type="text"
                  @click="
                    scope._self.$refs[
                      `popover-delete-${scope.$index}`
                    ].doClose()
                  "
                >取消</el-button>
                <el-button
                  type="primary"
                  size="mini"
                  @click="deleteClick(scope)"
                >确定</el-button>
              </div>
              <el-button
                slot="reference"
                type="danger"
                style="height: 22px; line-height: 22px; padding: 0 10px"
                size="mini"
              >删除</el-button>
            </el-popover>
          </template>
        </el-table-column>
      </el-table>
      <el-row type="flex" justify="end" style="margin-top: 30px">
        <el-pagination
          background
          layout="total, sizes, prev, pager, next"
          :page-sizes="[10, 15, 20]"
          :page-size="pageSize"
          :current-page.sync="pageNum"
          :total="totalCount"
          @current-change="changePage"
          @size-change="sizeChange"
        />
      </el-row>
    </MyMain>

    <!--创建/编辑-->
    <el-dialog
      v-if="showDialog"
      class="dialog"
      :title="dialogType === 1 ? '添加安全组规则' : '修改安全组规则'"
      :visible="showDialog"
      width="600px"
      top="15vh"
      :close-on-click-modal="false"
      @close="showDialog = false"
    >
      <el-form ref="form" :rules="rules" :model="form" label-width="auto">
        <el-form-item label="规则方向" prop="direction">
          <el-select
            v-model="form.direction"
            placeholder="请选择规则方向"
            style="width: 100%"
          >
            <el-option
              v-for="item in directionOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="协议类型" prop="protocol">
          <el-select
            v-model="form.protocol"
            placeholder="请选择协议类型"
            style="width: 100%"
          >
            <el-option
              v-for="item in protocolOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item
          v-if="form.protocol !== 'ICMP'"
          label="端口范围"
          prop="portRange"
        >
          <el-row type="flex" align="middle">
            <el-input
              v-model="form.portRange"
              placeholder="例：80,90,8108"
              :disabled="isCloudAliyun && form.protocol === 'ALL'"
            />
            <el-tooltip
              class="item"
              effect="dark"
              content="“80,90,8108”表示80，90，8108三个端口；“1/65535”表示端口1到端口65535"
              placement="top"
            >
              <i
                class="el-icon-info icon"
                style="font-size: 18px; margin-left: 10px"
              ></i>
            </el-tooltip>
          </el-row>
        </el-form-item>
        <el-form-item label="授权策略" prop="policy">
          <el-select
            v-model="form.policy"
            placeholder="请选择授权策略"
            style="width: 100%"
          >
            <el-option
              v-for="item in policyOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
              :disabled="isCloudPrivate && item.value == '拒绝'"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="授权对象" prop="authObj">
          <el-input
            v-model="form.authObj"
            placeholder="例：10.x.y.z/32"
            type="textarea"
            :rows="3"
          />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="showDialog = false">取 消</el-button>
        <el-button
          type="primary"
          size="small"
          :loading="dialogConfirmLoading"
          @click="dialogConfirmClick"
        >确 定</el-button>
      </div>
    </el-dialog>
  </MyContainer>
</template>

<script>
import pagePermissionMixin from '@/views/mixin/pagePermission.js'
import pageQueryMixin from '@/views/mixin/pageQuery.js'
import MyContainer from '@/components/Layout/MyContainer.vue'
import MyHeader from '@/components/Layout/MyHeader.vue'
import MyMain from '@/components/Layout/MyMain.vue'
import { isEmptyString } from '@/utils'
import { isCloudPublic } from '@/utils/constant'
import {
  getNSGRuleList,
  createNSGRule,
  deleteNSGRule,
  updateNSGRule
} from '@/api/cn-resource'

// 默认form
const getDefaultForm = () => {
  return {
    direction: '',
    protocol: '',
    portRange: '',
    policy: '',
    authObj: ''
  }
}

export default {
  name: 'NSGMgmtRule',
  components: {
    MyContainer,
    MyHeader,
    MyMain
  },
  mixins: [pagePermissionMixin, pageQueryMixin],
  data() {
    const validatePortRange = (rule, value, callback) => {
      if (
        (isEmptyString(value) && isEmptyString(this.form.protocol)) ||
        (!isEmptyString(value) && !isEmptyString(this.form.protocol))
      ) {
        callback()
      } else {
        callback(new Error('端口范围和协议类型只能同时为空或同时不为空'))
      }
    }
    return {
      nsgId: '',
      isCloudPrivate: true,
      cloudProvider: '',
      directionOptions: [
        {
          label: '入栈',
          value: '入栈'
        },
        {
          label: '出栈',
          value: '出栈'
        }
      ],
      protocolOptions: [
        {
          label: 'TCP',
          value: 'TCP'
        },
        {
          label: 'UDP',
          value: 'UDP'
        },
        {
          label: 'ICMP',
          value: 'ICMP'
        }
      ],
      policyOptions: [
        {
          label: '允许',
          value: '允许'
        },
        {
          label: '拒绝',
          value: '拒绝'
        }
      ],
      showDialog: false,
      dialogType: 1, // 1-创建 2-编辑
      form: getDefaultForm, // 表单
      // 校验规则
      rules: {
        direction: [
          { required: true, message: '请选择规则方向', trigger: 'change' }
        ],
        // protocol: [
        //   { required: true, message: '请选择协议类型', trigger: 'change' }
        // ],
        portRange: [{ trigger: 'blur', validator: validatePortRange }],
        policy: [
          { required: true, message: '请选择授权策略', trigger: 'change' }
        ],
        authObj: [
          { required: true, message: '请输入授权对象', trigger: 'blur' }
        ]
      },
      dialogConfirmLoading: false
    }
  },
  computed: {
    /**
     * @description: 是否阿里云
     * @return {*}
     */
    isCloudAliyun() {
      return this.cloudProvider === '阿里云'
    }
  },
  watch: {
    /**
     * @description: 监听协议类型
     * @return {*}
     */
    'form.protocol': {
      handler(newVal) {
        if (this.isCloudAliyun && newVal === 'ALL') {
          // 阿里云 且 协议类型 选择了 全部
          this.form.portRange = '-1/-1'
        } else if (newVal === 'ICMP') {
          if (this.isCloudPrivate) {
            this.form.portRange = ''
          } else if (this.isCloudAliyun) {
            this.form.portRange = '-1/-1'
          }
        }
      },
      immediate: true
    }
  },
  created() {
    this.nsgId = this.$route.query.nsgId || ''
    this.cloudProvider = this.$route.query.cloudProvider || ''
    this.isCloudPrivate = !isCloudPublic(this.cloudProvider)
    if (this.isCloudAliyun) {
      // 阿里云 协议类型 多一个 全部
      this.protocolOptions.unshift({
        label: '全部',
        value: 'ALL'
      })
      // 阿里云 端口范围不能为空
      this.rules.portRange.push({
        required: true,
        message: '请输入端口范围'
      })
    }
  },
  methods: {
    /**
     * @description: 确定
     * @return {*}
     */
    dialogConfirmClick() {
      // 校验
      this.$refs.form.validate((valid, obj) => {
        if (valid) {
          // 合法
          this.dialogConfirmLoading = true
          if (this.dialogType === 1) {
            createNSGRule({
              nsgId: this.nsgId,
              ...this.form
            })
              .then((res) => {
                this.$message.success({
                  message: '创建安全组规则成功！',
                  duration: '2000'
                })
                this.showDialog = false // 取消弹窗
                this.pageNum = 1 // 第一页
                this.getList() // 刷新数据
              })
              .finally(() => {
                this.dialogConfirmLoading = false
              })
          } else if (this.dialogType === 2) {
            updateNSGRule({
              ...this.form
            })
              .then((res) => {
                this.$message.success({
                  message: '修改安全组成功！',
                  duration: '2000'
                })
                this.showDialog = false // 取消弹窗
                this.getList() // 刷新数据
              })
              .finally(() => {
                this.dialogConfirmLoading = false
              })
          }
        }
      })
    },
    /**
     * @description: 编辑
     * @param {*} row
     * @return {*}
     */
    editClick(row) {
      this.form = JSON.parse(JSON.stringify(row)) // 获取表单数据
      this.dialogType = 2 // 编辑弹窗
      this.showDialog = true // 展示
    },
    /**
     * @description: 创建
     * @return {*}
     */
    createClick() {
      this.$refs.form && this.$refs.form.resetFields() // 表单重置
      this.form = getDefaultForm() // 初始化form
      this.dialogType = 1 // 创建弹窗
      this.showDialog = true // 展示
    },
    /**
     * @description: 删除
     * @param {*} row
     * @param {*} index
     * @return {*}
     */
    deleteClick(scope) {
      const row = scope.row
      deleteNSGRule({
        id: row.id
      }).then((res) => {
        scope._self.$refs[`popover-delete-${scope.$index}`].doClose() // 取消popover
        this.$message.success('删除成功')
        if (this.list.length === 1) {
          // 当前页只有一条数据时 删除完刷新上一页数据
          this.pageNum = Math.max(this.pageNum - 1, 1)
        }
        this.getList() // 请求数据
      })
    },
    /**
     * @description: 获取列表
     * @return {*}
     */
    getList() {
      this.handleRequestAndResp(getNSGRuleList, {
        nsgId: this.$route.query.nsgId,
        pageNum: this.pageNum,
        pageSize: this.pageSize
      })
    }
  }
}
</script>

<style lang="less" scoped>
@import "@/assets/css/common.less";
.container {
}
</style>
